﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "GcmpModelInterface.h"
#include "CollaborationScope.h"

namespace gcmp
{
    class UniIdentity;
    class IGraphicsMaterial;
    class IGraphicsMaterialData;

    /// \brief 图形材质管理器
    class GCMP_MODEL_INTERFACE_EXPORT IGraphicsMaterialManager
    {
    public:
        /// \brief 析构函数
        virtual ~IGraphicsMaterialManager();
        
        /// \brief 通过某类别的类别UniIdentity，获取其图形材质的id
        /// \param categoryUid 类别的UniIdentity
        /// \return 图形材质的id
        virtual ElementId GetGraphicsMaterialIdByCategoryUid(const UniIdentity& categoryUid) const = 0;

        /// \brief 为某类别创建图形材质
        /// 
        /// 内建类别的图形材质不需要用户创建，系统会自动创建，
        /// 只有那些非内建的针对类别的图形材质才需要用户调用此函数来创建，且不能重复创建
        /// 创建出来的图形材质是未绑定材质实例的，如果需要显示材质就需要绑定一个材质实例
        /// \param categoryUid 类别的UniIdentity
        /// \return 图形材质的id
        virtual ElementId CreateGraphicsMaterialForCategory(const UniIdentity& categoryUid) = 0;

        /// \brief 获取与指定图形材质具有相同材质实例的所有图形材质的id
        ///
        /// 多个图形材质之间可以共享材质实例，根据传入的图形材质，查找得到所有与其共享材质实例的所有图形材质的Id（包括传入的图形材质的Id）
        /// 其中一个用途为获取与当前图形材质共享材质实例的无类别图形材质，在记录材质实例数据到脚本时，需要有一个记录一个id来标识该材质实例，可以用无类别的图形材质的ElementUid
        /// \param pGraphicsMaterial 指定的图形材质，若为空将会报错
        /// \return 与传入图形材质具有相同材质实例的所有图形材质Id
        virtual std::vector<ElementId> GetAllGraphicsMaterialsBindingWithTheSameMaterialInstance(const IGraphicsMaterial *pGraphicsMaterial) const = 0;
      
        /// \brief 上传协同项目的材质数据和对应的贴图文件。
        ///
        /// 暂时上传的贴图文件包括diffuse_texture,normal_texture,backDiffuse_texture
        ///
        /// \param collaborationContext 协同基本信息。包括项目Id、协同影响范围、专业（在影响范围为CollaborationScope::Specialty时有效）
        /// \param category2MaterialString 要上传的<类别的Guid, 对应的材质实例转成的Json字符串>集合
        /// \param isMandatoryCoverMaterialString 是否强制上传材质数据字符串。为true时，用新数据强制覆盖云端数据，为false时,当某一项云端有更新，则该项不会上传
        /// \param isMandatoryCoverTextureFile 是否强制上传材质贴图文件。为true时，用新数据强制覆盖云端数据，为false时,若云端存在该文件，则不会上传
        /// \param deleteAllBeforeUpload 上传前是否删除表格中的数据
        /// \param[out] pErrorMessage 如果传入不为空，发生错误时传出错误信息
        /// \return bool 成功-true；失败-false
        /// \note 只在协同环境下有效，否则返回false
        virtual bool Upload(const CollaborationContext& collaborationContext, const std::map<Guid, std::wstring, GuidComparer>& category2MaterialString,
            bool isMandatoryCoverMaterialString, bool isMandatoryCoverTextureFile, bool deleteAllBeforeUpload, std::wstring* pErrorMessage) = 0;
     
        /// \brief 下载该协同项目的材质所需的贴图并得到对应的材质信息字符串
        ///
        /// 通过指定项目Id，协同影响范围，类别Guid，可以下载并得到相关项目材质数据。
        /// 下载的贴图文件会放在如C:\Users\...\AppData\Local\Temp\文件夹中
        /// 得到的材质数据materialJsonString已经不是原生的，而是根据默认的贴图路径修改过的，可使用IGraphicsMaterial::UpdateMaterialInstanceByJsonString()来更新材质
        ///
        /// \param collaborationContext 协同基本信息。包括项目Id、协同影响范围、专业（在影响范围为CollaborationScope::Specialty时有效）
        /// \param categoryGuid 类别的Guid
        /// \param materialJsonString 得到的材质实例的json字符串
        /// \param isMandatoryCoverTextureFile 是否强制覆盖下载贴图文件（不论本地是否存在）
        /// \param[out] pErrorMessage 如果传入不为空，发生错误时传出错误信息
        /// \return bool 成功-true；失败-false
        /// \note 只在协同环境下有效，否则返回false
        virtual bool Download(const CollaborationContext& collaborationContext, const Guid& categoryGuid,
            std::wstring& materialJsonString, bool isMandatoryCoverTextureFile, std::wstring* pErrorMessage) = 0;

        /// \brief 回调函数
        ///
        /// \param[out] wstring  传入对应的材质id
        /// \param[out] ElementId  最终得到的材质elementId
        /// \param[out] const int&  正常 = 0 参数错误 =5000 请求超时 = 6000 权限错误 = 7000(token错误) 资源不存在 = 8000 网络错误 = 9000(token为空)
        typedef std::function<void(const std::wstring&, const ElementId&, const int&)> MaterialLoadCallback;

        /// \brief 创建云端材质模板创建材质回调函数
        /// \param *func  T对象的函数指针
        /// \param object  T对象
        template<typename T>
        static MaterialLoadCallback CreateMaterialLoadCallback(void (T::*func)(const std::wstring&, const ElementId&, const int&), T* object)
        {
            if (object)
            {
                return std::bind(func, object, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
            }
            return nullptr;
        }

        /// \brief 通过云端材质模板创建材质（异步处理回调函数）
        ///
        /// 请保证token得正确性：只要有过正确得token下载过材质，本地就会有缓存。
        /// 而只要本地有缓存，就算token错误，也可以拿到材质。
        /// \param userToken 用户token账号
        /// \param libId 下载的库id
        /// \param materialGuid 所需下载的材质id（对应于云材质库中的guid，请去云材质库中查找）
        /// \param productCode 产品代码，必须是产品从aecore获取的appkey值，保证其唯一性
        /// \param MaterialLoadCallback 下载成功/失败后调用。返回的ElementId无效则下载失败，期间gcmp内部会有DBG_WARN弹窗提醒失败
        virtual void CreateGraphicsMaterialFromCloudLibrary(const std::wstring& userToken, const std::wstring& libId, const std::wstring& materialGuid, const std::wstring& productCode, MaterialLoadCallback materialCallback) = 0;

        /// \brief 通过本地材质模板创建材质
        ///
        /// \param materialGuid 材质guid（对应于本地材质库中的guid，请在本地材质库中查找MaterilLocal文件）
        /// \return 返回得到的材质id，若失败返回无效ID
        virtual ElementId CreateGraphicsMaterialFromLocalLibrary(const std::wstring& materialGuid) = 0;

        /// \brief 批量重载图形材质
        /// 
        /// 所有节点的材质都会被重载
        /// 注意：此处是批量处理到重载到IGraphicsNodeStyleAndMaterialOverride中
        /// 不要再事务外使用该接口
        /// \param elementIdToMaterialId 所需重载的elementId与其对应materialId集合。
        virtual void OverrideGraphicsMaterial(const std::map<ElementId, ElementId>& elementIdToMaterialId) = 0;

        /// \brief 批量重载图形材质
        /// 
        /// 所有节点的材质都会被重载
        /// 注意：此处是批量处理到重载到IGraphicsNodeStyleAndMaterialOverride中
        /// 不要再事务外使用该接口
        /// \param elementIds，待重載的Id集，elementIds中不应该包含临时id
        /// \param materialId 图形材质的 id; 如果 id 是无效的，相当于取消重载图形材质
        virtual void OverrideGraphicsMaterial(const std::set<ElementId>& elementIds, const ElementId& materialId) = 0;

    };
}

